package cn.edu.xmu.restfuldemo.dao;

import cn.edu.xmu.restfuldemo.mapper.GoodsMapper;
import cn.edu.xmu.restfuldemo.model.*;
import cn.edu.xmu.restfuldemo.util.RedisUtil;
import cn.edu.xmu.restfuldemo.util.ResponseCode;
import cn.edu.xmu.restfuldemo.util.ReturnObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.List;

import static cn.edu.xmu.restfuldemo.util.Common.*;
/**
 * @author Ming Qiu
 **/
@Repository
public class GoodsDao {

    private Logger logger = LoggerFactory.getLogger(GoodsDao.class);

    @Autowired
    private GoodsMapper goodsMapper;

    @Autowired
    private RedisUtil redisUtil;

    @Value("${restfuldemo.goods.expiretime}")
    private long goodsTimeout;

    /**
     * 用GoodsPo对象找Goods对象
     * @param goodsPo 条件对象，所有条件为AND，仅有索引的值可以作为条件
     * @param withProduct 是否带关联的Product（有性能问题，不要一次返回太多Goods对象）
     * @return  Goods对象列表，带关联的Product返回
     */
    public ReturnObject<List<Goods>> findGoods(GoodsPo goodsPo, Boolean withProduct){
        logger.info("findGoods: goodsPo =" + goodsPo+" withProduct = "+withProduct);

        List<Goods> retGoods = null;
        String key = null;
        if (null != goodsPo.getId() && withProduct){
            key = "g_"+goodsPo.getId();
            Goods goods = (Goods) redisUtil.get(key);
            if (null != goods){
                logger.info("findGoods: hit redis cache, key = "+key);
                retGoods = new ArrayList<>(1);
                retGoods.add(goods);
                return new ReturnObject<>(retGoods);
            }
        }

        List<GoodsPo> goodsPos = goodsMapper.findGoods(goodsPo);
        logger.info("findGoods: goodsPos =" + goodsPos);
        retGoods = new ArrayList<>(goodsPos.size());
        ProductPo productPo = null;

        if (withProduct) {
            productPo = new ProductPo();
        }

//        for (GoodsPo goodsItem : goodsPos) {
//            Goods item = new Goods(goodsItem);
//            if (withProduct) {
//                productPo.setGoodsId(goodsItem.getId());
//                List<ProductPo> productPos = goodsMapper.findProduct(productPo);
//                List<Product> productList = new ArrayList<>(productPos.size());
//                for (ProductPo productItem : productPos) {
//                    Product product = new Product(productItem);
//                    product = getEffectivePrice(product);
//                    productList.add(product);
//                }
//                item.setProductList(productList);
//            }
//            retGoods.add(item);
//        }

        if (null != goodsPo.getId() && withProduct){
            logger.info("findGoods: put into redis cache, key = "+key);
            if (retGoods.size() != 0) {
                redisUtil.set(key, retGoods.get(0), goodsTimeout);
            }else{
                redisUtil.set(key, null, goodsTimeout);
            }
        }

        logger.info("findGoods: retGoods = "+retGoods +", withProduct ="+withProduct);
        return new ReturnObject<>(retGoods);
    }

    public ReturnObject<List<Product>> findProduct(ProductPo productPo, Boolean withProduct){
        logger.info("findProducts: productPo =" + productPo);

        List<Product> retProduct = null;
        String key = null;
        if (null != productPo.getId() && withProduct){
            key = "g_"+productPo.getId();
            Product product = (Product) redisUtil.get(key);
            if (null != product){
                logger.info("findProduct: hit redis cache, key = "+key);
                retProduct = new ArrayList<>(1);
                retProduct.add(product);
                return new ReturnObject<>(retProduct);
            }
        }



        List<ProductPo> productPos = goodsMapper.findProduct(productPo);
        logger.info("findProduct: productPos =" + productPos);
        retProduct = new ArrayList<>(productPos.size());
        GoodsPo goodsPo = null;

        if (withProduct) {
            goodsPo = new GoodsPo();
        }

        for (ProductPo productItem : productPos) {
            Product item = new Product(productItem);
            if (withProduct) {
                goodsPo.setId(productItem.getGoodsId());
                List<GoodsPo> goodsPos = goodsMapper.findGoods(goodsPo);
                List<Goods> goodsList = new ArrayList<>(goodsPos.size());
                for (GoodsPo goodsItem : goodsPos) {
                    Goods goods = new Goods(goodsItem);
                    goodsList.add(goods);
                }
                item.setGoodsList(goodsList);
            }
            retProduct.add(item);
        }

        if (null != productPo.getId() && withProduct){
            logger.info("findGoods: put into redis cache, key = "+key);
            if (retProduct.size() != 0) {
                redisUtil.set(key, retProduct.get(0), goodsTimeout);
            }else{
                redisUtil.set(key, null, goodsTimeout);
            }
        }

        logger.info("findProduct: retProduct = "+retProduct +", withProduct ="+withProduct);
        return new ReturnObject<>(retProduct);
    }

    public ReturnObject<List<Product>> findProductNoRedis(ProductPo productPo, Boolean withProduct){
        logger.info("findProducts: productPo =" + productPo);

        List<Product> retProduct = null;
        String key = null;



        List<ProductPo> productPos = goodsMapper.findProduct(productPo);
        logger.info("NoRedis");
        retProduct = new ArrayList<>(productPos.size());
        GoodsPo goodsPo = null;

        if (withProduct) {
            goodsPo = new GoodsPo();
        }

        for (ProductPo productItem : productPos) {
            Product item = new Product(productItem);
            if (withProduct) {
                goodsPo.setId(productItem.getGoodsId());
                List<GoodsPo> goodsPos = goodsMapper.findGoods(goodsPo);
                List<Goods> goodsList = new ArrayList<>(goodsPos.size());
                for (GoodsPo goodsItem : goodsPos) {
                    Goods goods = new Goods(goodsItem);
                    goodsList.add(goods);
                }
                item.setGoodsList(goodsList);
            }
            retProduct.add(item);
        }

        logger.info("findProduct: retProduct = "+retProduct +", withProduct ="+withProduct);
        return new ReturnObject<>(retProduct);
    }





}
